package cn.snow.boot.datasource;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;
import java.util.HashMap;

/**
 * 动态多数据源配置
 *
 * @author liuwanxiang
 * @version 2019/05/28
 */
@Configuration
@EnableTransactionManagement
@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "com.alibaba.druid.pool.DruidDataSource", matchIfMissing = false)
public class DynamicDataSourceConfiguration {

    @Value("${spring.datasource.type}")
    private Class<? extends DataSource> dataSourceType;

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.primary")
    public DataSource primaryDatasource(){
        return DataSourceBuilder.create().type(dataSourceType).build();
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.config")
    public DataSource configDatasource(){
        return DataSourceBuilder.create().type(dataSourceType).build();
    }

    @Bean
    @Primary
    public AbstractRoutingDataSource dataSource(DataSource primaryDatasource, DataSource configDatasource){
        DynamicDatasource datasource = new DynamicDatasource();
        HashMap<Object, Object> map = new HashMap<>(4);
        map.put(DbName.PRIMARY,primaryDatasource);
        map.put(DbName.CONFIG,configDatasource);
        datasource.setDefaultTargetDataSource(primaryDatasource);
        datasource.setTargetDataSources(map);
        datasource.afterPropertiesSet();
        return datasource;
    }

    /**
     * 根据数据源创建SqlSessionFactory
     */
    @Bean
    public SqlSessionFactory sqlSessionFactory(@Qualifier("primaryDatasource") DataSource primaryDatasource,
                                               @Qualifier("configDatasource") DataSource configDatasource) throws Exception {
        SqlSessionFactoryBean fb = new SqlSessionFactoryBean();
        // ATTENTION: 指定数据源(这个必须有，用来解决循环引用，否则报错)
        fb.setDataSource(dataSource(primaryDatasource,configDatasource));
        return fb.getObject();
    }

}
